package com.bicntech.system.service.impl;


import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bicntech.common.enums.InspectStateEnum;
import com.bicntech.common.exception.ServiceException;
import com.bicntech.common.helper.LoginHelper;
import com.bicntech.common.utils.ObjectUtil;
import com.bicntech.system.dto.*;
import com.bicntech.system.entity.OutfieldVehicleEquipmentInspect;
import com.bicntech.system.mapper.OutfieldVehicleEquipmentInspectMapper;
import com.bicntech.system.service.OutfieldVehicleEquipmentInspectService;
import com.bicntech.system.service.PersonnelPerformanceManagementService;
import com.bicntech.system.vo.OutfieldStateStatisticsVO;
import com.bicntech.system.vo.OutfieldTypeStatisticsVO;
import com.google.common.collect.ImmutableList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 *
 * @author bicntech
 * @description:机务维修记录--外场 服务实现类
 * </p>
 * @date 2022-08-02
 */
@Slf4j
@Service
public class OutfieldVehicleEquipmentInspectServiceImpl extends ServiceImpl<OutfieldVehicleEquipmentInspectMapper, OutfieldVehicleEquipmentInspect> implements OutfieldVehicleEquipmentInspectService {

    @Resource
    private OutfieldVehicleEquipmentInspectMapper outfieldVehicleEquipmentInspectMapper;

    @Resource
    private PersonnelPerformanceManagementService performanceManagementService;

    @Override
    public IPage<OutfieldVehicleEquipmentInspectDTO> listOutfieldVehicleEquipmentInspectsByPage(IPage<OutfieldVehicleEquipmentInspect> iPage, OutfieldInspectQueryDTO query) {

        return super.page(iPage, this.queryWrapper(query)).convert(ObjectUtil.transform(OutfieldVehicleEquipmentInspectDTO.class));
    }

    @Override
    public List<OutfieldVehicleEquipmentInspect> selectList(OutfieldInspectQueryDTO query) {
        return super.list(this.queryWrapper(query));
    }

    @Override
    public List<OutfieldVehicleEquipmentInspectDTO> listOutfieldVehicleEquipmentInspects(OutfieldVehicleEquipmentInspectDTO outfieldVehicleEquipmentInspectDTO) {
        QueryWrapper<OutfieldVehicleEquipmentInspect> queryWrapper = new QueryWrapper<OutfieldVehicleEquipmentInspect>();
        //TODO 这里需要自定义用于匹配的字段,并把wrapper传入下面的page方法
        return ObjectUtil.deepCopyList(super.list(queryWrapper), OutfieldVehicleEquipmentInspectDTO.class);
    }

    @Override
    public OutfieldVehicleEquipmentInspectDTO getOutfieldVehicleEquipmentInspectById(Long id) {
        OutfieldVehicleEquipmentInspectDTO outfieldVehicleEquipmentInspectDTO = ObjectUtil.entityToModel(super.getById(id), OutfieldVehicleEquipmentInspectDTO.class);
        return outfieldVehicleEquipmentInspectDTO;
    }

    @Override
    public Long addOutfieldVehicleEquipmentInspect(OutfieldInspectAddDTO request) {
        if (checkExistence(request)) {
            throw new ServiceException("工单已存在");
        }
        OutfieldVehicleEquipmentInspect outfieldVehicleEquipmentInspect = ObjectUtil.entityToModel(request, OutfieldVehicleEquipmentInspect.class);
        //生成code
        String code;
        do {
            code = "W" + LocalDate.now().toString().replace("-", "") + RandomUtil.randomNumbers(6);
        } while (checkCode(code));

        outfieldVehicleEquipmentInspect.setCode(code);
        outfieldVehicleEquipmentInspect.setState(InspectStateEnum.TO_BE_CHECKED.getDescription());

        if (super.save(outfieldVehicleEquipmentInspect)) {
            log.info("插入outfieldVehicleEquipmentInspect成功,id为{}", outfieldVehicleEquipmentInspect.getId());
            return outfieldVehicleEquipmentInspect.getId();
        } else {
            throw new ServiceException("添加失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long deleteOutfieldVehicleEquipmentInspectById(Long id) {
        Optional.ofNullable(super.getById(id))
                .filter(f -> InspectStateEnum.HISTORY.getDescription().equals(f.getState()))
                .ifPresent(this::deduction);
        if (super.removeById(id)) {
            return id;
        } else {
            throw new ServiceException("删除失败[id=" + id + "]");
        }
    }

    @Override
    public Long updateOutfieldVehicleEquipmentInspect(OutfieldInspectWorkerDTO inspectWorkerDTO) {
        OutfieldVehicleEquipmentInspect equipmentInspect = checkCodeState(inspectWorkerDTO.getId(), InspectStateEnum.TO_BE_CHECKED);
        Integer inspectType = equipmentInspect.getType();
        Date inspectDate = equipmentInspect.getInspectDate();
        if (!equipmentInspect.getState().equals(InspectStateEnum.HISTORY.getDescription())) {
            equipmentInspect.setState(InspectStateEnum.TO_BE_REVIEWED.getDescription());
        } else {
            //若为完成的工单，撤销之前工作者增加的分数
            performanceManagementService.recallMark(equipmentInspect.getWorkerId(), 2, Long.valueOf(inspectType), inspectDate);
            //若为完成的工单，增加当前工作者的分数
            performanceManagementService.addMark(LoginHelper.getUserId().toString(), 2, Long.valueOf(inspectType), inspectDate);
        }

        if (ObjectUtil.notEmpty(inspectWorkerDTO.getIsFinish()) && inspectWorkerDTO.getIsFinish()) {
            if (!ObjectUtil.equals(inspectType, 3)) {
                throw new ServiceException("非维修检查工单，禁止此操作");
            }
            performanceManagementService.addMark(LoginHelper.getUserId().toString(), 2, Long.valueOf(inspectType), inspectDate);
            equipmentInspect.setState(InspectStateEnum.HISTORY.getDescription());
        }
        equipmentInspect.setInspectTime(new Date());
        equipmentInspect.setWorker(inspectWorkerDTO.getName());
        equipmentInspect.setWorkerId(LoginHelper.getUserId().toString());
        equipmentInspect.setWorkerInspectTerm(inspectWorkerDTO.getInspectDTOS());

        if (super.updateById(equipmentInspect)) {
            return equipmentInspect.getId();
        } else {
            throw new ServiceException("更新失败[id=" + equipmentInspect.getId() + "]");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long toExamine(OutfieldAuditWorkerDTO inspectWorkerDTO) {
        OutfieldVehicleEquipmentInspect equipmentInspect = checkCodeState(inspectWorkerDTO.getId(), InspectStateEnum.TO_BE_REVIEWED);
        Integer inspectType = equipmentInspect.getType();
        Date inspectDate = equipmentInspect.getInspectDate();
        boolean isHistory = InspectStateEnum.HISTORY.getDescription().equals(equipmentInspect.getState());
        if (isHistory) {
            //若为完成的工单，撤销之前复核者增加的分数
            performanceManagementService.recallMark(equipmentInspect.getReviewerId(), 2, Long.valueOf(inspectType), inspectDate);
            //若为完成的工单，增加当前复核者的分数
            performanceManagementService.addMark(LoginHelper.getUserId().toString(), 2, Long.valueOf(inspectType), inspectDate);
        }
        equipmentInspect.setState(InspectStateEnum.HISTORY.getDescription());
        equipmentInspect.setReviewerTime(new Date());
        equipmentInspect.setReviewer(inspectWorkerDTO.getName());
        equipmentInspect.setReviewerId(LoginHelper.getUserId().toString());
        equipmentInspect.setReviewerInspectTerm(inspectWorkerDTO.getInspectDTOS());
        if (super.updateById(equipmentInspect)) {
            if (!isHistory) {
                String reviewerId = equipmentInspect.getReviewerId();
                String workerId = equipmentInspect.getWorkerId();
                performanceManagementService.addMark(reviewerId, 2, Long.valueOf(inspectType), inspectDate);
                performanceManagementService.addMark(workerId, 2, Long.valueOf(inspectType), inspectDate);
            }
            return equipmentInspect.getId();
        } else {
            throw new ServiceException("更新失败[id=" + equipmentInspect.getId() + "]");
        }
    }

    @Override
    public Long updateHeadById(OutfieldInspectAddDTO inspectWorkerDTO) {
        Long id = inspectWorkerDTO.getId();
        Date inspectDate = inspectWorkerDTO.getInspectDate();
        String flightNumber = inspectWorkerDTO.getFlightNumber();
        String machineNumber = inspectWorkerDTO.getMachineNumber();
        String stand = inspectWorkerDTO.getStand();
        Integer type = inspectWorkerDTO.getType();

        OutfieldVehicleEquipmentInspect inspect = super.getById(id);
        if (InspectStateEnum.HISTORY.getDescription().equals(inspect.getState())) {
            throw new ServiceException("工单已完成禁止修改");
        }

        if (checkExistence(inspectWorkerDTO)) {
            throw new ServiceException("工单已存在");
        }

        inspect.setInspectDate(inspectDate);
        inspect.setMachineNumber(machineNumber);
        inspect.setFlightNumber(flightNumber);
        inspect.setStand(stand);

        if (!inspect.getType().equals(type)) {
            inspect.setType(type);
            inspect.setState(InspectStateEnum.TO_BE_CHECKED.getDescription());
            inspect.setWorkerInspectTerm(Collections.emptyList());
            inspect.setReviewerInspectTerm(Collections.emptyList());
        }
        if (super.updateById(inspect)) {
            return inspect.getId();
        } else {
            throw new ServiceException("更新失败[id=" + inspect.getId() + "]");
        }
    }

    @Override
//    @Transactional(rollbackFor = Exception.class)
    public Boolean disuseById(Long id) {
        OutfieldVehicleEquipmentInspect equipmentInspect = super.getById(id);
//        this.deduction(equipmentInspect);
        equipmentInspect.setState(InspectStateEnum.DISUSE.getDescription());
        return super.updateById(equipmentInspect);
    }

    @Override
    public List<OutfieldStateStatisticsVO> stateStatistics() {
        List<OutfieldStateStatisticsVO> stateStatisticsVOList = outfieldVehicleEquipmentInspectMapper.stateStatistics();
        for (Integer state : ImmutableList.of(1, 2, 3, 4)) {
            if (stateStatisticsVOList.stream().noneMatch(a -> ObjectUtil.equals(a.getState(), state))) {
                stateStatisticsVOList.add(new OutfieldStateStatisticsVO().setState(state).setCount(0L));
            }
        }
        return stateStatisticsVOList;
    }

    @Override
    public List<OutfieldTypeStatisticsVO> typeStatistics() {
        List<OutfieldTypeStatisticsVO> typeStatisticsVOList = outfieldVehicleEquipmentInspectMapper.typeStatistics();
        for (Integer type : ImmutableList.of(1, 2, 3, 4)) {
            if (typeStatisticsVOList.stream().noneMatch(a -> ObjectUtil.equals(a.getType(), type))) {
                typeStatisticsVOList.add(new OutfieldTypeStatisticsVO().setType(type).setCount(0L));
            }
        }
        return typeStatisticsVOList;
    }

    @Override
    public Boolean deleteExpire(Integer validationDays) {
        LambdaQueryWrapper<OutfieldVehicleEquipmentInspect> wrapper = new LambdaQueryWrapper<>();
        wrapper.le(OutfieldVehicleEquipmentInspect::getCreateTime, LocalDateTime.now().minusDays(validationDays));
        return super.remove(wrapper);
    }

    public boolean checkExistence(OutfieldInspectAddDTO request) {
        return lambdaQuery()
                .eq(OutfieldVehicleEquipmentInspect::getInspectDate, request.getInspectDate())
                .eq(OutfieldVehicleEquipmentInspect::getFlightNumber, request.getFlightNumber())
                .eq(OutfieldVehicleEquipmentInspect::getMachineNumber, request.getMachineNumber())
                .eq(OutfieldVehicleEquipmentInspect::getStand, request.getStand())
                .eq(OutfieldVehicleEquipmentInspect::getType, request.getType())
                .count() != 0;
    }

    public boolean checkCode(String code) {
        return lambdaQuery()
                .eq(OutfieldVehicleEquipmentInspect::getCode, code)
                .count() != 0;
    }

    public OutfieldVehicleEquipmentInspect checkCodeState(Long id, InspectStateEnum state) {
        OutfieldVehicleEquipmentInspect equipmentInspect = super.getById(id);
        if (equipmentInspect != null) {
//            if (!equipmentInspect.getState().equals(state.getDescription())) {
//                throw new ServiceException("工单状态不符合操作条件");
//            } else {
//                return equipmentInspect;
//            }
            return equipmentInspect;
        } else {
            throw new ServiceException("工单不存在");
        }

    }


    private LambdaQueryWrapper<OutfieldVehicleEquipmentInspect> queryWrapper(OutfieldInspectQueryDTO query) {
        return new LambdaQueryWrapper<OutfieldVehicleEquipmentInspect>()
                .eq(ObjectUtil.notEmpty(query.getType()), OutfieldVehicleEquipmentInspect::getType, query.getType())
                .eq(ObjectUtil.notEmpty(query.getState()), OutfieldVehicleEquipmentInspect::getState, query.getState())
                .like(ObjectUtil.notEmpty(query.getMachineNumber()), OutfieldVehicleEquipmentInspect::getMachineNumber, query.getMachineNumber())
                .like(ObjectUtil.notEmpty(query.getStand()), OutfieldVehicleEquipmentInspect::getStand, query.getStand())
                .like(ObjectUtil.notEmpty(query.getFlightNumber()), OutfieldVehicleEquipmentInspect::getFlightNumber, query.getFlightNumber())
                .ge(ObjectUtil.notEmpty(query.getStartTime()), OutfieldVehicleEquipmentInspect::getInspectDate, query.getStartTime())
                .le(ObjectUtil.notEmpty(query.getEndTime()), OutfieldVehicleEquipmentInspect::getInspectDate, query.getEndTime())
                .orderByDesc(OutfieldVehicleEquipmentInspect::getInspectDate);
    }


    private void deduction(OutfieldVehicleEquipmentInspect equipmentInspect) {
        String reviewerId = equipmentInspect.getReviewerId();
        String workerId = equipmentInspect.getWorkerId();
        Integer inspectType = equipmentInspect.getType();
        Date inspectDate = equipmentInspect.getInspectDate();
        performanceManagementService.recallMark(workerId, 2, Long.valueOf(inspectType), inspectDate);
        performanceManagementService.recallMark(reviewerId, 2, Long.valueOf(inspectType), inspectDate);

    }
}
